﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NewsMine.Storage;
using System.Threading;
using System.IO;

namespace NewsDiscoveryEngine
{
    public sealed class JobEngine:IDisposable
    {

        static object sharedResourceLock = new object();

        public string ID { get; set; }

        public JobPersistanceService PersistanceService { get; set; }
        public JobTrackingService JobTrackingService { get; set; }
        
        public IPersistedQueue QueueClient { get; set; }
        public IKeyValueStore keyStoreClient { get; set; }
        
        public DateTime StartTime { get; set; }
        public int ProcessedJobCount { get; set; }
        public string AgentName { get; set; }
        public TimeSpan EngineRecycleTimeSpan { get; set; }

        public List<Exception> Exceptions { get; set; }

        #region StopRequest property

        static object stopRequestSyncLock = new object();
        static bool isStopRequested = false;
        public static bool IsStopJobRequested { get
        {
            lock(stopRequestSyncLock)
            {
                return isStopRequested;
            }
        }
            set
            {
                isStopRequested = value;
            }
        }

        #endregion


        bool IsStopJobRequestedLocal = false;

        public delegate void JobEngineStoppedDelegate(JobEngine jobEngine);

        public event JobEngineStoppedDelegate JobEngineStopped;

        public JobEngine()
        {
           
            this.Exceptions = new List<Exception>();
        }

        public void RecordLiveStatus()
        {
            //todo: needs tobe implemented.
            // Here we need to poll the job engine status like processing / idle  etc.
        }

        DateTime startTime;

        public void ProcessJobs()
        {
            startTime = DateTime.Now;

            //todo: Look for persisted jobs in previous session and process them first.
            //need to implement...
            while (!IsStopJobRequested && !IsStopJobRequestedLocal)
            {
                /*
                 * Read the Queue and get the next job and process it.
                 */

                object jobObject = QueueClient.Dequeue();

                if (jobObject != null)
                {
                    //process the job

                    if (!(jobObject is BaseJob))
                    {
                        //Log error: saying that the queued object is not job.

                        this.Exceptions.Add(new ApplicationException("The incoming queued item is not job type "));

                        break;
                    }

                    BaseJob job = (BaseJob)jobObject;

                    job.OutputProduced += new BaseJob.OutputProducedDelegate(job_OutputProduced);

                    try
                    {
                        

                        job.ExecuteJob();
                    }
                    catch (Exception ex)
                    {
                        lock (sharedResourceLock)
                        {
                            NewsMine.Utilities.TempLogger.Log("\n\r" + "===============================" + "\n\r" + DateTime.Now.ToString() + "\n\r" + ex.Message + "\n\r" + job.GetType().Name + "\n\r" + ex.StackTrace,ex);
                        }
                    }
                }
                else
                {
                    Thread.Sleep(100);
                }

                if ((DateTime.Now - startTime) > EngineRecycleTimeSpan)
                    IsStopJobRequestedLocal = true;
            }

            JobEngineStopped(this);
        }

        void job_OutputProduced(BaseJob job, object outputObject)
        {
            //Create the output jobs and Queue up.
            try
            {
                if (job.WorkFlow != null)
                    job.WorkFlow.ProcessOutput(job, outputObject);
            }
            catch (Exception ex)
            {
                lock (sharedResourceLock)
                {
                    NewsMine.Utilities.TempLogger.Log( "\n\r" + "++++++++++++++++++++++++++++++++++++++" + "\n\r" + DateTime.Now.ToString() + "\n\r" + ex.Message + "\n\r" + job.GetType().Name + "\n\r" + ex.StackTrace,ex);
                }
            }
        }

        public void ProcessCommandFromJobManager()
        {
            //todo: needs to be implemented.
            // we may get commands from the job manager, that we need to consider before taking and processing next job.
            PollForJobManagerCommands();
            ProcessStopCommand();
            ProcessChangeInputQueueRequest();
            ProcessChangeQueueFilter();
        }

        private void ProcessChangeQueueFilter()
        {
            throw new NotImplementedException();
        }

        private void ProcessChangeInputQueueRequest()
        {
            throw new NotImplementedException();
        }

        private void ProcessStopCommand()
        {
            throw new NotImplementedException();
        }

        private void PollForJobManagerCommands()
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            throw new NotImplementedException();
        }
    }
}
